
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <vector>
#include <utility>
#include <time.h>

using namespace std;

#include "EasyBMP.h"

void getPixelData (int argc, char**argv, std::vector<std::pair<int, int>> *xy_values, std::vector<unsigned short *> *rgb_values);
void printValues(int n, std::vector<std::pair<int, int>> *xy_values, std::vector<unsigned char *> *rgb_values);

// Function 1
void PlusGen(int argc, char **argv)
{
	BMP MyImage;
	MyImage.ReadFromFile(argv[4]);
	
	int col = atoi(argv[2]);
	int row = atoi(argv[3]);

	for (int i = 0; i < MyImage.TellWidth(); i++){
		MyImage(i, col)->Red = 255;
		MyImage(i, col)->Blue = 0;
		MyImage(i, col)->Green = 0;
	}

	for (int j = 0; j < MyImage.TellHeight(); j++){
		MyImage(row, j)->Red = 255;
		MyImage(row, j)->Blue = 0;
		MyImage(row, j)->Green = 0;
	}

	MyImage.WriteToFile(argv[5]);
}

// Function 2
void ReadBMP(int argc, char **argv)
{
	BMP MyImage;
	MyImage.ReadFromFile(argv[4]);

	int i;
	int j;

	//// argv[2], argv[3] = jth row and ith column pixel value of the bmp
	sscanf(argv[2], "%d", &j);
	sscanf(argv[3], "%d", &i);

/*
	i = atoi(argv[2]);
	j = atoi(argv[3]);
	*/

	cout << "(" << (int) MyImage(i, j)->Red << ","
		<< (int) MyImage(i, j)->Green << ","
		<< (int) MyImage(i, j)->Blue << ","
		<< (int) MyImage(i, j)->Alpha << ")" << endl;
}
/*
// Function 3 -- This function determines the RGB values of a given pixel and assigns the integer values by reference.
void  RGB_Parser (int argc, char **argv, int col, int row,  *Red,  *Blue,  *Green)
{
	BMP MyImage;
	MyImage.ReadFromFile(argv[4]);
	
	&Red = (int) MyImage(col,row)->Red;
	&Green = (int) MyImage(col,row)->Green;
	&Blue = (int) MyImage(col,row)->Blue;
	
}
*/

//Function 4 -- This function gets the RGB values within a rectangular area(col1:col2, row1:row2) and assigns those values to 3 distinct arrays (Red, Green, and Blue) by reference.

// !!!! This is currently under development, so the input parameters are kluged !!!!

void RGB_Parser (int argc, char ** argv)  //(int col1, int row1, int col2, int row2, *Red, *Blue, *Green)
{	
	BMP MyImage;
	MyImage.ReadFromFile(argv[4]);

	int x1, x2, y1, y2;
	x1 = atoi(argv[5]);
	x2 = atoi(argv[6]);
	y1 = atoi(argv[7]);
	y2 = atoi(argv[8]);


	int Red[500], Green[500], Blue[500];

	int i, j, k;
	k = 0;

	for (i = x1; i < x2; i++) {
		for (j = y1; j < y2; j++) {
						
			Red[k] = (int) MyImage(i, j)->Red;
			Green[k] = (int) MyImage(i, j)->Green;
			Blue[k] = (int) MyImage(i, j)->Blue;
			k++;
		}
	}
	int t = 0;
	for (t = k-1 ; t >= 0; t--)
		cout << "Red: " << Red[t] << endl;
	for (t = k-1; t >= 0; t--)
		cout << "Green: " << Green[t] << endl;
	for (t = k-1; t >= 0; t--)
		cout << "Blue: " << Blue[t] << endl;
	}


//Function 5 -- This function takes parsed RGB information from function 4 and recreates that portion of the image.

void CopySegment (int argc, char ** argv)  //(int col1, int row1, int col2, int row2, *Red, *Blue, *Green)
{	
	BMP MyImage;
	MyImage.ReadFromFile(argv[4]);


	int x1, x2, y1, y2;
	x1 = atoi(argv[5]);
	x2 = atoi(argv[6]);
	y1 = atoi(argv[7]);
	y2 = atoi(argv[8]);

	
	
	int Red[5000], Green[5000], Blue[5000];

	int i, j, k;

	for (k=0, i = x1; i < x2; i++) {
		for (j = y1; j < y2; j++) {
						
			Red[k] = (int) MyImage(i, j)->Red;
			Green[k] = (int) MyImage(i, j)->Green;
			Blue[k] = (int) MyImage(i, j)->Blue;
			k++;
		}
	}
	
	BMP NewImage;												// establish a new image
	NewImage.SetSize(MyImage.TellWidth(), MyImage.TellHeight());  // make the size of the new image the same as the size of the entire original
	
	// changing the size of the image deletes all pixels, so we should have a clean bmp to put the segment onto

	//now I want to write the image segment

	for (k=0, i = x1; i < x2; i++) {
		for (j = y1; j < y2; j++)
		{
			NewImage(i,j)->Red = Red[k];
			NewImage(i,j)->Green = Green[k];
			NewImage(i,j)->Blue = Blue[k];
			k++;
		}
	}

	
	NewImage.WriteToFile(argv[9]);
}

//Function 6 -- this function is being used to test the speed of random RGB-pixel-info grabbing in large volume

//6.a This function creates the vector of xy pairs needed to test getPixelData
void createVector (int argc, char** argv, const int n, std::vector<std::pair<int, int>> *_out_xy_values)
{
	//this part ensures a random distribution of values across the bitmap
	BMP MyImage;
	MyImage.ReadFromFile(argv[4]);
	int height = MyImage.TellHeight();
	int width = MyImage.TellWidth();

	//this part generates the vector of xy pairs
	//pair<int, int> xy_pair;
	//vector<pair<int,int>> xy_Vals; 
	//int i = 0;
	
	for (int i = 0; i < n; i++) {
		
		//xy_pair.first = rand () % width;
		//xy_pair.second = rand () % height;

		//xy_Vals.push_back(xy_pair);
		_out_xy_values->push_back(make_pair
			(
				(int)(((float)rand() / (float)RAND_MAX) * width), 
				(int)(((float)rand() / (float)RAND_MAX) * height)
			)
		); 
	}

	return;
}



void getPixelData (int argc, char**argv, int n, std::vector<std::pair<int, int>> *xy_values, std::vector<unsigned char *> *_out_rgb_values)
{
	BMP MyImage;
	MyImage.ReadFromFile(argv[4]);

	std::vector<std::pair<int, int>>::iterator xy_it;
	std::vector<unsigned char *>::iterator rgb_it;

	xy_it = xy_values->begin();
	rgb_it = _out_rgb_values->begin();

	int x, y;

	for(int i = 0; i < n; i++){
		  
		x = xy_it->first;
		y = xy_it->second;

		unsigned char *rgbVal = *rgb_it;

		rgbVal[Red] = MyImage(x, y)->Red;
		rgbVal[Green] = MyImage(x, y)->Green;
		rgbVal[Blue] = MyImage(x, y)->Blue;

		//_out_rgb_values->push_back(rgbVal);

		xy_it++;
		rgb_it++; ///// DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     DEBUG     
	}
}


//main
int main (int argc, char **argv)
{
	srand (time (NULL) );
	
	switch(atoi(argv[1]))
	{
	case 0 :
		PlusGen(argc, argv);
		ReadBMP(argc, argv);
		break;

	case 1 :
		PlusGen(argc, argv);
		break;

	case 2 :
		ReadBMP(argc, argv);
		break;
	
	case 3 : 

	case 4 :
		RGB_Parser (argc, argv);
		break;

	case 5 :
		CopySegment (argc, argv);
		break;

	case 6 :

		const int n = 1000;
		std::vector<std::pair<int, int>> xyVals;
		std::vector<unsigned char *> rgbVals;

		xyVals.clear();
		rgbVals.clear();

		for(int i = 0; i < n; i++)
		{
			unsigned char *rgbVal = (unsigned char *)malloc(sizeof(unsigned char) * 3);
			rgbVals.push_back(rgbVal);
		}

		
		createVector(argc, argv, n, &xyVals);
		
		clock_t t1, t2; //timing part 1/2
		t1 = clock ();

		getPixelData(argc, argv, n, &xyVals, &rgbVals);
//		printValues(n, &xyVals, &rgbVals);

		t2 = clock(); //timing part 2/2
		float diff ((float) t2 - (float) t1);
		cout << "Timing Information : " << diff * ((double)1000 / CLOCKS_PER_SEC) << "ms" << endl;

		std::vector<unsigned char *>::reverse_iterator rit;
		for(rit = rgbVals.rbegin(); rit != rgbVals.rend(); rit++)
		{
			free(*rit);
		}
		rgbVals.clear();

		break;
	}

	return 0;
}

void printValues(int n, std::vector<std::pair<int, int>> *xy_values, std::vector<unsigned char *> *rgb_values)
{
//	cout << "(x, y) : (r, g, b)" << endl;

	std::vector<std::pair<int, int>>::iterator xy_it;
	std::vector<unsigned char *>::iterator rgb_it;

	xy_it = xy_values->begin();
	rgb_it = rgb_values->begin();

	for(int i = 0; i < n; i++)
	{
		std::pair<int, int> xy_vals = *xy_it;
		unsigned char *rgb_vals = *rgb_it;

		cout << "(" << xy_vals.first << ", " << xy_vals.second << ")" <<
			" : " << "(" << (int)rgb_vals[0] << ", " << (int)rgb_vals[1] << ", " << (int)rgb_vals[2] << ")" << endl;

		xy_it++;
		rgb_it++;
	}

			
}

